package com.wzy.flowable.flow.Controller;

import com.wzy.flowable.flow.service.FlowableProcessDefinitionService;
import com.wzy.flowable.flow.service.IFlowableProcessInstanceService;
import com.wzy.flowable.flow.vo.ProcessDefinitionVo;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.FlowNode;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.common.engine.impl.util.IoUtil;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author: wzy
 * @Date: 2022/02/06/11:57
 * @Description:
 */
@RestController
@Slf4j
@RequestMapping("/level01")
public class TestLevel01Controller {
    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private TaskService taskService;
    @Autowired
    private ProcessEngine processEngine;

    @Autowired
    private FlowableProcessDefinitionService flowableProcessDefinitionService;

    @Autowired
    private IFlowableProcessInstanceService flowableProcessInstanceService;

    @Autowired
    private IdentityService identityService;

    @PostMapping("/test/{filename}")
    public void deployment(@PathVariable("filename") String filename) {

        /*
         * @Date: 2021/10/17 23:38
         * Step 1: 部署xml（压缩到zip形式，直接xml需要配置相对路径，麻烦，暂不用）
         */
      /*  try {
            File zipTemp = new File("f:/complex-approval.bpmn20.zip");
            ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zipTemp));
            Deployment deployment = repositoryService
                    .createDeployment()
                    .addZipInputStream(zipInputStream)
                    .deploy();
            log.info("部署成功:{}", deployment.getId());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }*/
        RepositoryService repositoryService = processEngine.getRepositoryService();
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("flowable/" + filename)
                .name("complex-approval审批流程部署")
                .deploy();

        /*
         * @Date: 2021/10/17 23:40
         * Step 2: 查询部署的流程定义
         */
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionKey("complex-approval").list();
        List<ProcessDefinition> pages = repositoryService.createProcessDefinitionQuery().processDefinitionKey("complex-approval").listPage(1, 30);
    }

    @GetMapping("/start/{processKey}")
    public void startProcess(@PathVariable("processKey") String processKey) {
        /*
         * @Date: 2021/10/17 23:40
         * Step 3: 启动流程，创建实例
         */
        String processDefinitionKey = processKey;//流程定义的key,对应complex-approval的流程图
        String businessKey = "stu_level";//业务代码，根据自己的业务用
        Map<String, Object> variablesDefinition = new HashMap<>();//流程变量，可以自定义扩充
        variablesDefinition.put("reason", "有事请假");
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variablesDefinition);
        log.info("启动成功:{}", processInstance.getId());

        /*
         * @Date: 2021/10/17 23:40
         * Step 4: 查询指定流程所有启动的实例列表
         * 列表，或 分页 删除
         */
        List<Execution> executions = runtimeService.createExecutionQuery().processDefinitionKey("complex-approval").list();
        List<String> activityIds = executions.stream().map(x -> x.getActivityId()).collect(Collectors.toList());

        List<Execution> executionPages = runtimeService.createExecutionQuery().processDefinitionKey("complex-approval").listPage(1, 30);
//        runtimeService.deleteProcessInstance(processInstanceId, deleteReason); //删除实例
    }

    @GetMapping("/stu/{assignee}/{command}")
    public String compute(@PathVariable(value = "assignee") String assignee, @PathVariable(value = "command") String command) {
        /*
         * @Date: 2021/10/17 23:40
         * Step 5: 学生查询可以操作的任务,并完成任务
         */
        String users = assignee; //候选组 xml文件里面的 flowable:candidateGroups="stu_group"
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(users).orderByTaskCreateTime().desc().list();
        for (Task task : taskList) {
            Map<String, Object> result = new HashMap<>();
            // 完成
            result.put("command", command);
            taskService.addComment(task.getId(), task.getProcessInstanceId(), "同意");
            taskService.complete(task.getId(), result);
        }
        List<Execution> executions = runtimeService.createExecutionQuery().processDefinitionKey("complex-approval").list();
        ProcessInstance processInstance =
                runtimeService.startProcessInstanceByKey("complex-approval", "stu_lev");
        List<String> activityIds = executions.stream().map(x -> x.getProcessInstanceId()).collect(Collectors.toList());
        activityIds.forEach(currentActivityId -> {

            BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
            FlowNode flowNode = (FlowNode) bpmnModel.getFlowElement(currentActivityId);
            SequenceFlow sequenceFlow = flowNode.getIncomingFlows().get(0);
            // 获取上一个节点的activityId
            String sourceRef = sequenceFlow.getSourceRef();
        });
        /*
         * @Date: 2021/10/18 0:17
         * Step 7: 历史查询，因为一旦流程执行完毕，活动的数据都会被清空，上面查询的接口都查不到数据，但是提供历史查询接口
         */
        // 历史流程实例
        List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("complex-approval").list();
        // 历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("complex-approval").list();
        return "提交审批";
    }
    @GetMapping("/teacher/{assignee}")
    public String approve_teacher(@PathVariable(value = "assignee") String assignee) {
        /*
         * @Date: 2021/10/17 23:40
         * Step 5: 学生查询可以操作的任务,并完成任务
         */
        String users = assignee; //候选组 xml文件里面的 flowable:candidateGroups="stu_group"
        List<Task> taskList = taskService.createTaskQuery().taskAssignee(users).orderByTaskCreateTime().desc().list();
        for (Task task : taskList) {
            Map<String, Object> result = new HashMap<>();
            // 完成
            result.put("commond", "agree");
            taskService.complete(task.getId(), result);
        }
        /*
         * @Date: 2021/10/18 0:17
         * Step 7: 历史查询，因为一旦流程执行完毕，活动的数据都会被清空，上面查询的接口都查不到数据，但是提供历史查询接口
         */
        // 历史流程实例
        List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("complex-approval").list();
        // 历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("complex-approval").list();
        return "审批完成";
    }

    @RequestMapping("/approvl")
    public String approvl() {
        String candidateGroupTe = "mte_group"; //候选组 xml文件里面的 flowable:candidateGroups="te_group"
        List<Task> taskListTe = taskService.createTaskQuery().taskCandidateGroup(candidateGroupTe).orderByTaskCreateTime().desc().list();
        for (Task task : taskListTe) {
            // 申领任务
            taskService.claim(task.getId(), "学生complex-approval流程");
            // 完成
            Map<String, Object> variables = new HashMap<>();
            variables.put("command", "agree"); //携带变量，用于网关流程的条件判定，这里的条件是同意
            taskService.complete(task.getId(), variables);
        }
        // 历史流程实例
        List<HistoricProcessInstance> historicProcessList = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("complex-approval").list();
        // 历史任务
        List<HistoricTaskInstance> historicTaskList = historyService.createHistoricTaskInstanceQuery().processDefinitionKey("complex-approval").list();
        return "校长审批流程结束！！";
    }
    /**
     * 通过id和类型获取图片
     *
     * @param id       定义id
     * @param type     类型
     * @param response response
     */
    @GetMapping(value = "/processFile/{type}/{id}")
    public void processFile(@PathVariable String id, @PathVariable String type, HttpServletResponse response) {
        try {
            byte[] b = null;
            ProcessDefinitionVo pd = flowableProcessDefinitionService.getById(id);
            if (pd != null) {
                if (type.equals("xml")) {
                    response.setHeader("Content-type", "text/xml;charset=UTF-8");
                    InputStream inputStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getResourceName());
                    b = IoUtil.readInputStream(inputStream, "image inputStream name");
                } else {
                    response.setHeader("Content-Type", "image/png;charset=UTF-8");
                    InputStream inputStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), pd.getDgrmResourceName());
                    b = IoUtil.readInputStream(inputStream, "image inputStream name");
                }
                response.getOutputStream().write(b);
            }
        } catch (Exception e) {
            log.error("ApiFlowableModelResource-loadXmlByModelId:" + e);
            e.printStackTrace();
        }
    }

    /**
     * 流程跟踪
     * @param processInstanceId
     * @param response
     */
    @GetMapping(value = "/image/{processInstanceId}")
    public void image(@PathVariable String processInstanceId, HttpServletResponse response) {
        try {
            byte[] b = flowableProcessInstanceService.createImage(processInstanceId);
            response.setHeader("Content-type", "image/png;charset=UTF-8");
            response.getOutputStream().write(b);
        } catch (Exception e) {
            log.error("ApiFormDetailReource-image:" + e);
            e.printStackTrace();
        }
    }
    /**
     * 删除流程定义
     *
     * @param deploymentId 部署id
     */
    @PostMapping(value = "/deleteDeployment")
    public String deleteDeployment(String deploymentId) {
        repositoryService.deleteDeployment(deploymentId, true);
        return "SUCCESS";
    }
}
